import ajax, { AjaxRequestConfig, AjaxResponse } from "uni-ajax";
import { config } from "@/config";
import { usePage, useToast, useLogin, useClipboard } from '@/hooks';
import { ApiCode, BaseApi } from "@/types/api/base";
import { useMyStore } from "@/stores";

const { error } = useToast()
const { reload, navigate } = usePage()
const { copy } = useClipboard()

const _ajax = ajax.create({
	baseURL: config.serverUrl,
	timeout: 2000,
})

/**设置请求头 */
const getHeader = (data?: Record<string, string>) => {
	const userStore = useMyStore();

	let header: Record<string, string> = {
		// 'X-App-Platform': 'h5',
		// 'X-App-Version': '1.0',
		'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
		...data
	};
	if (userStore.accessToken) {
		header['X-Token'] = `Bearer ${userStore.accessToken}`
	}
	return header
}

/**
 * 请求拦截器
 */
_ajax.interceptors.request.use((c: AjaxRequestConfig) => {
	c.header = getHeader()
	return c;
})

/**
 * 响应拦截
 */
_ajax.interceptors.response.use((res: AjaxResponse<BaseApi<any>>) => {
	const { data } = res
	apiStatusCode(data.code, data.msg, data.data)
	return res
}, err => {
	browserStatusCode(err.statusCode)
	return Promise.reject(err)
})

/**请求 */
export const request = {
	async get<T>(url: string, data?: any) {
		return (await _ajax.get<BaseApi<T>>(url, data)).data
	},

	async post<T>(url: string, data?: any) {
		return (await _ajax.post<BaseApi<T>>(url, data)).data
	},
}

/**
 * 上传文件
 * @param url 服务器上传地址
 * @param opt.filePath 要上传文件资源的路径
 * @param opt.formData HTTP 请求中其他额外的 form data
 * @param opt.callback 回调uploadTask,可监听上传进度变化事件,以及取消上传任务
 * @returns 
 */
export const upload = <T>(url: string, opt: {
	filePath: string,
	formData: Record<string, string>,
	callback?: (task: UniApp.UploadTask) => void
}) => {
	return new Promise<BaseApi<T>>((resolve, reject) => {
		const header = getHeader({
			'Content-Type': 'multipart/form-data',
		})
		const uploadTask = uni.uploadFile({
			url: config.serverUrl + url,
			filePath: opt.filePath,
			name: 'file',
			header,
			formData: typeof opt.formData === 'object' ? opt.formData : {},
			success: (req) => {
				console.log(req);
				const res = JSON.parse(req.data) as BaseApi<T>
				apiStatusCode(res.code, res.msg, res.data)
				resolve(res)
			},
			fail: (err) => {
				browserStatusCode(500, err.errMsg)
				reject()
			}
		})
		if (opt.callback && typeof opt.callback === 'function') {
			opt.callback(uploadTask)
		}
	})
}

/**请求错误弹窗 */
const alertError = (code: number, msg: string, data: unknown) => {
	let confirmText = '刷新页面';
	//#ifdef MP-ALIPAY
	confirmText = '确认';
	//#endif
	uni.showModal({
		title: '网络错误',
		content: '网络开了小差，请刷新重试下哦~',
		cancelText: '复制错误',
		confirmText: confirmText,
		success: (e) => {
			if (e.cancel) {
				const text = `code: ${code}, \r\nmsg: ${msg}, \r\ndetail: ` + (data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null);
				copy(text)
			}
			if (e.confirm) {
				// #ifndef MP-ALIPAY
				reload();
				// #endif
			}
		},
	});
};

/**处理服务器结果 */
const apiStatusCode = (code: number, msg: string, data: unknown) => {
	if (code === -1) {
		error('请重新登陆！')
		return navigate(config.loginPage)
	} else if (code === ApiCode.systemError) {
		alertError(code, msg, data)
	}

}

/**处理请求结果 */
const browserStatusCode = (statusCode: number, msg: string = '服务器内部错误', data?: BaseApi<unknown>) => {
	let code = 500
	switch (statusCode) {
		case 404:
			code = 404
			msg = '资源获取不到'
			break;
		case 500:
			code = 500
			msg = '服务器内部错误'
			break;
		case 503:
			code = 503
			msg = '服务不可用'
			break;
		case 504:
			code = 504
			msg = '网关超时'
			break;
		case 400:
			code = 400
			msg = '服务器不理解请求的语法'
			break;
		case 403:
			code = 403
			msg = '服务器拒绝请求'
			break;
		case 405:
			code = 405
			msg = '方法禁用'
			break;
		case 406:
			code = 406
			msg = '无法使用请求的内容特性响应请求的网页'
			break;
		case 407:
			code = 407
			msg = '需要代理授权'
			break;
		case 408:
			code = 408
			msg = '请求超时'
			break;
		case 409:
			code = 409
			msg = '冲突'
			break;
		case 410:
			code = 410
			msg = '已删除'
			break;
		case 411:
			code = 411
			msg = '需要有效长度'
			break;
		case 412:
			code = 412
			msg = '服务器未满足请求者在请求中设置的其中一个前提条件'
			break;
		case 413:
			code = 413
			msg = '请求实体过大'
			break;
		case 414:
			code = 414
			msg = '求情URI过长'
			break;
		case 415:
			code = 415
			msg = '不支持的媒体类型'
			break;
		case 416:
			code = 416
			msg = '请求范围不符合要求'
			break;
		case 417:
			code = 417
			msg = '未满足期望值'
			break;
	}
	alertError(code, msg, data)
};